﻿using System;
using System.Collections.Generic;
using System.IO;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Parameter;
using Microsoft.Web.Administration;
using PSE.Deployment.SetupBase.Parameter.Enums;

namespace PSE.Deployment.SetupBase.Steps
{
    public class InstallWcfService : SetupStep<Configuration.Actions.InstallWcfService>
    {
        public InstallWcfService(IStepGroup parent, Group group, Configuration.Actions.InstallWcfService action, Parameter.Enums.SetupMode setupMode)
            : base(parent, group, action, setupMode)
        {
            this.ResetProgress();
        }

        public override void Execute()
        {
            this.ResetProgress();

            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                InstallServices();
            }
            else if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
            {
                UninstallServices();
            }
        }

        public override void Undo()
        {
            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                UninstallServices();
            }
        }

        private void InstallServices()
        {
            //if (SetupMainFactory.GetInstance().Parameter.Prerequisites.IIS7 == PrerequisitesStatus.NotOk)
            //{
            InstallServicesOnHoster();
            //}
            //else
            //{
            //    InstallServicesOnIIS();
            //}
        }

        private void InstallServicesOnHoster()
        {
            foreach (WcfService service in Action.Services)
            {
                if (this.IsStopped())
                    return;

                IEnumerable<string> files;
                string destination = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, service.Folder.Destination);

                if (service.Folder.Files.Count == 0)
                {
                    files = Directory.GetFiles(destination, "*.dll", SearchOption.AllDirectories);
                }
                else
                {
                    files = PSE.Deployment.Util.File.GetFiles(destination, service.Folder.Files);
                }

                string packageName = SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.Id + "_" + service.ProcessName;

                PSE.Deployment.Util.WcfService.AddPackage(service.ServerName, packageName);

                foreach (string source in files)
                {
                    if (this.IsStopped())
                        return;

                    string file;

                    if (Path.IsPathRooted(source))
                    {
                        file = source;
                    }
                    else
                    {
                        file = Path.Combine(destination, source);
                    }

                    if (file.EndsWith("Service.dll") || file.EndsWith("ServiceImplementation.dll"))
                    {
                        this.IncrementProgress(file);

                        this.AddUsedBy(file);

                        PSE.Deployment.Util.WcfService.AddAssembly(service.ServerName, packageName, file);
                    }
                }

                PSE.Deployment.Util.WcfService.StartPackage(service.ServerName, packageName);
            }
        }

        private void InstallServicesOnIIS()
        {
            foreach (WcfService wcfService in Action.Services)
            {
                using (ServerManager iisManager = new ServerManager())
                {
                    string systemId = SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.Id;

                    this.IncrementProgress(wcfService.Path);

                    ApplicationPool pool = iisManager.ApplicationPools[systemId + wcfService.ProcessName];

                    if (pool == null)
                    {
                        pool = iisManager.ApplicationPools.Add(systemId + wcfService.ProcessName);
                        pool.Enable32BitAppOnWin64 = true;
                        pool.ProcessModel.IdentityType = ProcessModelIdentityType.LocalSystem;
                    }

                    Site site = iisManager.Sites[systemId];

                    Application application;

                    if (site != null)
                    {
                        if (site.Applications[wcfService.Path] == null)
                        {
                            application = site.Applications.CreateElement("application");
                            application.Path = wcfService.Path;
                            application.ApplicationPoolName = systemId + wcfService.ProcessName;
                            application.EnabledProtocols = "http,net.tcp,net.pipe";
                            application.VirtualDirectories.Add("/", Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, wcfService.Folder.Destination));
                            site.Applications.Add(application);
                        }
                    }
                    else
                    {
                        throw new Exception(string.Format("O site {0} não existe", systemId));
                    }

                    this.AddUsedBy(wcfService.Path);

                    iisManager.CommitChanges();
                }
            }
        }

        private void UninstallServices()
        {
            //if (SetupMainFactory.GetInstance().Parameter.Prerequisites.IIS7 == PrerequisitesStatus.NotOk)
            //{
            UninstallServicesOnHoster();
            //}
            //else
            //{
            //    UninstallServicesOnIIS();
            //}
        }

        private void UninstallServicesOnHoster()
        {
            List<InstalledArtefact> files = GetUsedFiles();

            for (int i = files.Count - 1; i >= 0; i--)
            {
                if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall && this.IsStopped())
                    break;

                if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
                    this.IncrementProgress(files[i].ArtefactName);
                else
                    this.DecrementProgress(files[i].ArtefactName);

                this.RemoveUsedBy(files[i].ArtefactName);

                System.Threading.Thread.Sleep(200);
            }

            foreach (WcfService service in Action.Services)
            {
                string packageName = SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.Id + "_" + service.ProcessName;

                try
                {
                    PSE.Deployment.Util.WcfService.RemovePackage(service.ServerName, packageName);
                }
                catch (Exception ex)
                {
                    SetupMainFactory.GetInstance().WriteStepLog(this, string.Format("Não foi possível remover o pacote {0} do servidor {1}", packageName, service.ServerName), ex);                   
                }

                try
                {
                    PSE.Deployment.Util.WcfService.RemovePackage(service.ServerName, service.ProcessName);
                }
                catch (Exception ex1)
                {
                    SetupMainFactory.GetInstance().WriteStepLog(this, string.Format("Não foi possível remover o pacote {0} do servidor {1}", service.ProcessName, service.ServerName), ex1);
                }
            }
        }

        private void UninstallServicesOnIIS()
        {
            List<InstalledArtefact> files = GetUsedFiles();

            using (ServerManager iisManager = new ServerManager())
            {
                for (int i = files.Count - 1; i >= 0; i--)
                {
                    if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall && this.IsStopped())
                        break;

                    if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
                        this.IncrementProgress(files[i].ArtefactName);
                    else
                        this.DecrementProgress(files[i].ArtefactName);

                    ApplicationPool pool = iisManager.ApplicationPools[files[i].ArtefactName.Replace("/", "")];

                    if (pool != null)
                    {
                        iisManager.ApplicationPools.Remove(pool);
                    }

                    string systemId = SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.Id;

                    Site site = iisManager.Sites[systemId];

                    if (site != null)
                    {
                        Application application = site.Applications[files[i].ArtefactName];

                        if (site != null)
                        {
                            site.Applications.Remove(application);
                        }
                    }

                    iisManager.CommitChanges();

                    this.RemoveUsedBy(files[i].ArtefactName);
                }
            }
        }

        private void ResetProgress()
        {
            //if (SetupMainFactory.GetInstance().Parameter.Prerequisites.IIS7 == PrerequisitesStatus.NotOk)
            //{
            ResetProgressOnHoster();
            //}
            //else
            //{
            //    ResetProgress(Action.Services.Count);
            //}
        }

        private void ResetProgressOnHoster()
        {
            int count = 0;

            foreach (WcfService service in Action.Services)
            {
                if (service.Folder.Files.Count == 0)
                {
                    string destination;

                    if (Directory.Exists(SetupMainFactory.GetInstance().Parameter.InstalationSource))
                        destination = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstalationSource, service.Folder.Source);
                    else
                        destination = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, service.Folder.Destination);

                    count += PSE.Deployment.Util.File.CountFiles(destination, "*Service.dll");

                    count += PSE.Deployment.Util.File.CountFiles(destination, "*ServiceImplementation.dll");
                }
                else
                {
                    foreach (string file in service.Folder.Files)
                    {
                        if (file.EndsWith("Service.dll") || file.EndsWith("ServiceImplementation.dll"))
                        {
                            count++;
                        }
                    }
                }
            }

            this.ResetProgress(count);
        }
    }
}
